// Copyright  2004-2008 Backplane Ltd.
//
// This file is part of Ubiquity formsPlayer
//
// Ubiquity formsPlayer is free software; you can redistribute it and/or modify it
// under the terms of the GNU General Public License as published by the
// Free Software Foundation; either version 3 of the License, or (at your
// option) any later version.
//
// Ubiquity formsPlayer is distributed in the hope that it will be useful, but WITHOUT
// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
// FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
// more details.
//
// You should have received a copy of the GNU General Public License
// along with Ubiquity formsPlayer If not, see <http://www.gnu.org/licenses/>.
//	
//
//   Purpose: implementation of CXFormsElementUpload.
//   $Id$



#include "stdafx.h"
#include "XForms.h"
#include "XFormsApp.h"

#include "uploadui.h"
#include "upload.h"
#include "parseUpload.h"
#include "formcontrol.h"
#include "Afxdlgs.h"
#include <registrylookup.h>
#include <registrylookup_i.c>
#include <base64_i.c>
#include <Common/Registry/msw/RegistryUtils.h>

typedef CComPtr<IFileInfo> IFileInfoPtr;
CXFormsElementUpload::CXFormsElementUpload()
: m_sFileExtensionFilter("All files (*.*)|*.*||")
{
	m_guidEvents = DIID_HTMLSelectElementEvents;
	m_lGUIStringID = IDS_XFormsElementGUI_Upload;
	m_pCodec.CoCreateInstance(CLSID_codec);
	
//	m_pEncoder.CreateInstance(BASE64Lib::CLSID_EncodingStream,(IUnknown*)m_pEncoder);
}

CXFormsElementUpload::~CXFormsElementUpload()
{
//	if(m_pInStream)
//		delete m_pInStream;

}


CImpl* CXFormsElementUpload::CreateImpl()
{
	return (CImpl*) new CImplUpload(this);
}


HRESULT CXFormsElementUpload::get_value(BSTR* psValue)
{
	HRESULT hr;
	if(m_pImpl && reinterpret_cast<CImplUpload*>(m_pImpl)->m_bGetBinaryData)
	{
		CComBSTR s;
		try
		{
			m_pCodec->encodeStream(&s);
			// Bug Once we've got our data we can close the file as the next time the
			// user selects a file we get the data again!
			m_pCodec->closeFile();
			hr = S_OK;
		}
		catch(_com_error)
		{
			//normally the input stream has not been initialised
			//		not an error, could be that we have decided
			//		not to upload anything.
			s = L"";
			hr = S_FALSE;
		}
		*psValue  = s.Detach();
	}
	else
	{
		hr = getURIValue(psValue);
	}
	return hr;
};

HRESULT CXFormsElementUpload::attachEvents(IHTMLDocument3 * /*pDoc3*/)
{
	HRESULT hr = S_FALSE;
	if(m_pEventSink)
	{
	
		hr =  AtlAdvise
		(
			m_pControl
			, (IDispatch*) m_pEventSink
			, m_guidEvents
			, &m_dwCookie
		);
	}
	return hr;

}

HRESULT CXFormsElementUpload::handleEvent(DISPID eventID, VARIANT *pvarResult, DISPPARAMS *pdispparams)
{
	HRESULT hr;
	switch (eventID) 
	{
		case DISPID_HTMLINPUTTEXTELEMENTEVENTS_ONCHANGE:
		case DISPID_IHTMLSELECTELEMENT_ONCHANGE:
			hr = getBinaryStream();
			break;
		default:
			hr = CXFormsElement::handleEvent(eventID,pvarResult,pdispparams);
			break;
	}
	return hr;
}

HRESULT CXFormsElementUpload::getBinaryStream()
{
	AFX_MANAGE_STATE(AfxGetStaticModuleState())

	HRESULT hr = S_FALSE;
	CComQIPtr<IHTMLSelectElement> pSel(m_pControl);
	if(pSel)
	{
		CComBSTR sAction;
		pSel->get_value(&sAction);
		if(sAction == L"upload")
		{
			//upload is the title value, do nothing.
			hr = S_FALSE;
		}
		else if(sAction==L"browse")
		{
			//Get the user to select a file
			CFileDialog oDlg
			(
				TRUE
				,0
				,0
				,0
				,m_sFileExtensionFilter
				,0);
			int iResponse = oDlg.DoModal();
			if(IDOK == iResponse)
			{
				m_sFilePath = oDlg.GetPathName();
				m_sFileName = oDlg.GetFileName();
				// We only need to get the file if we're going to use the data.
				if(m_pImpl && reinterpret_cast<CImplUpload*>(m_pImpl)->m_bGetBinaryData) {
					try
					{
						_bstr_t sFilePath(m_sFilePath);
						hr = m_pCodec->openFile(sFilePath);
					}
					catch(_com_error)
					{
						hr = E_FAIL;
					}
				}
				
				CComBSTR sVal;
				get_value(&sVal);
				if(m_pFormControl)
					hr = m_pFormControl->putValue(sVal);
			}
			else
			{
				hr = S_FALSE;
			}
			//Return the appearance of the control to origianl state, showing the upload title.
			CComBSTR sUpload(L"upload");
			pSel->put_value(sUpload);
		}
		else
		{
			// some kind of direct get method, invoke the appropriate
			//	application
		}

	}

	return hr;
}


CXFormsParse* CXFormsElementUpload::CreateParse(CImpl* pImpl)
{
	CXFormsParse* pParse = new CXFormsParseUpload((CImplUpload*) pImpl);

	return pParse;
}


// <summary>Gets the URI of the bound data</summary>
HRESULT CXFormsElementUpload::getURIValue(BSTR * psValue)
{
	HRESULT hr = S_FALSE;
	if(!::isEmpty(m_sFilePath))
	{
		CStringW sURI;
		sURI.Format(L"file://%s" , m_sFilePath);
		*psValue = sURI.AllocSysString();
		hr = S_OK;
	}
	return hr;
}
HRESULT CXFormsElementUpload::getSignificantDescendentNodes(IHTMLDocument3 * pDoc3)
{
	//Fudge.  object not rendered by new method,
	//	but events handled by new method.
	HRESULT hr = __super::getSignificantDescendentNodes(pDoc3);
	m_bNewMethod = true;
	return hr;
}

HRESULT CXFormsElementUpload::get_mimeType(BSTR * psValue)
{
	HRESULT hr = S_FALSE;
	try
	{
		IFileInfoPtr pFileInfo;
		hr = pFileInfo.CoCreateInstance(CLSID_FileInfo);
		if(pFileInfo)
		{
			CComBSTR sFileName(m_sFileName);
			CComBSTR sValue;
			pFileInfo->mimeTypeFromExtension(sFileName,&sValue);
			*psValue = sValue.Detach();
			hr = S_OK;
		}
	}
	catch(_com_error e)
	{
		hr = E_FAIL;
	}
	return S_OK;
}

HRESULT CXFormsElementUpload::get_filename(BSTR * psValue)
{
	m_sFileName.CopyTo(psValue);
	return S_OK;
}

HRESULT CXFormsElementUpload::put_value(BSTR /*sValue*/)
{
	//put_value is invalid on the upload UI, it is 
	//	a write-only control, and does not
	//	reflect the data, although it will
	//	display validity/relevance etc.
	return S_FALSE;
};

//TODO: is this specialisation of this function necessary?
HRESULT CXFormsElementUpload::ElementReady(void)
{
	HRESULT hr = __super::ElementReady();

	if(SUCCEEDED(hr))
		SetFileExtensionFilter(reinterpret_cast<CImplUpload*>(m_pImpl)->m_sMediatype);

	return hr;
}

void CXFormsElementUpload::SetFileExtensionFilter(BSTR sMediaType)
{
	if(sMediaType && *sMediaType != L'\0')
	{
		CString sRegistryKey, sNewFilter;
		for(unsigned int i = 0; i <= wcslen(sMediaType); ++i)
		{
			if(sMediaType[i] == L' ' || sMediaType[i] == L'\t' || sMediaType[i] == L'\r' || sMediaType[i] == L'\n' || sMediaType[i] == L'\0')
			{
				wchar_t cNext = sMediaType[i];
				sMediaType[i] = L'\0';
				if(i > 0)
				{
					char *sFileExtension = 0;
					sRegistryKey.Format("MIME\\Database\\Content Type\\%S", sMediaType);
					if(SUCCEEDED(xport::RegGetValueString(HKEY_CLASSES_ROOT, sRegistryKey, "Extension", &sFileExtension)) && sFileExtension)
					{
						if(*sFileExtension != '\0')
						{
							sNewFilter.Format("%S (*%s)|*%s|", sMediaType, sFileExtension, sFileExtension);
							m_sFileExtensionFilter.Insert(0, sNewFilter);
						}

						free(sFileExtension);
					}
				}
				if(cNext == L'\0')
					break;
				sMediaType[i] = cNext;
				sMediaType += i + 1;
				i = -1;
			}
		}
	}
}
